package com.flyqiu.flow.core.manage;

import com.flyqiu.flow.api.script.IVarSerialize;
import com.flyqiu.flow.api.script.FlyQiuFlowVarSerializeManage;
import com.flyqiu.flow.api.script.VarSerialize;
import com.flyqiu.flow.core.var.*;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class DefaultFlyQiuFlowVarSerializeManage implements FlyQiuFlowVarSerializeManage {
    private List<ConverterWrapper> variableConverters;
    private Map<String, IVarSerialize> serializeMap;


    public DefaultFlyQiuFlowVarSerializeManage() {
        variableConverters = new ArrayList<>();
        initDefault();
    }

    private void initDefault() {
        variableConverters.add(new ConverterWrapper(new BigDecimalConverter(), Integer.MAX_VALUE - 16000));
        variableConverters.add(new ConverterWrapper(new BooleanConverter(), Integer.MAX_VALUE - 15000));
        variableConverters.add(new ConverterWrapper(new ByteConverter(), Integer.MAX_VALUE - 14000));
        variableConverters.add(new ConverterWrapper(new CharConverter(), Integer.MAX_VALUE - 13000));
        variableConverters.add(new ConverterWrapper(new DateConverter(), Integer.MAX_VALUE - 12000));
        variableConverters.add(new ConverterWrapper(new DoubleConverter(), Integer.MAX_VALUE - 11000));
        variableConverters.add(new ConverterWrapper(new FloatConverter(), Integer.MAX_VALUE - 10000));
        variableConverters.add(new ConverterWrapper(new IntConverter(), Integer.MAX_VALUE - 9000));
        variableConverters.add(new ConverterWrapper(new LocalDateConverter(), Integer.MAX_VALUE - 8000));
        variableConverters.add(new ConverterWrapper(new LocalDateTimeConverter(), Integer.MAX_VALUE - 7000));
        variableConverters.add(new ConverterWrapper(new LocalTimeConverter(), Integer.MAX_VALUE - 6000));
        variableConverters.add(new ConverterWrapper(new LongConverter(), Integer.MAX_VALUE - 5000));
        variableConverters.add(new ConverterWrapper(new ShortConverter(), Integer.MAX_VALUE - 4000));
        variableConverters.add(new ConverterWrapper(new JSONArrayConverter(), Integer.MAX_VALUE - 3000));
        variableConverters.add(new ConverterWrapper(new JSONObjectConverter(), Integer.MAX_VALUE - 2000));
        variableConverters.add(new ConverterWrapper(new StringConverter(), Integer.MAX_VALUE - 1000));
        variableConverters.add(new ConverterWrapper(new BeanConverter(), Integer.MAX_VALUE));
        reloadPriority();
    }

    @Override
    public List<? extends IVarSerialize> converters() {
        return variableConverters;
    }

    @Override
    public void register(IVarSerialize converter, int priority) {
        ConverterWrapper wrapper = new ConverterWrapper(converter, priority);
        variableConverters.add(wrapper);
        this.reloadPriority();
    }

    private void reloadPriority() {
        variableConverters = variableConverters.stream().sorted(Comparator.comparing(e -> e.priority)).collect(Collectors.toList());
        serializeMap = variableConverters.stream().map(e -> e.converter).collect(Collectors.toMap(IVarSerialize::type, e -> e, (e1, e2) -> e2));
    }

    @Override
    public VarSerialize serialize(Object val) {
        if (val == null) {
            return null;
        }
        String clazzName = val.getClass().getName();
        if (serializeMap.containsKey(clazzName)) {
            IVarSerialize iVarSerialize = serializeMap.get(clazzName);
            return iVarSerialize.serialize(this, val);
        }
        VarSerialize varSerialize = null;
        for (ConverterWrapper wrapper : variableConverters) {
            if (!wrapper.isType(this, val)) {
                continue;
            }
            VarSerialize template = wrapper.serialize(this, val);
            if (template == null || template.getVarData() == null) {
                continue;
            }
            varSerialize = template;
            if (!template.isNext()) {
                break;
            }
        }
        if (varSerialize == null) {
            throw new RuntimeException("Could not find a converter for this data type :" + val.getClass().getName());
        }
        return varSerialize;
    }

    @Override
    public VarSerialize serialize(Object val, String varType) {
        if (val == null) {
            throw new RuntimeException("Serialized object cannot be null");
        }
        if (!serializeMap.containsKey(varType)) {
            throw new RuntimeException("Could not find a converter for this data type :" + varType);
        }
        IVarSerialize converter = serializeMap.get(varType);
        return converter.serialize(this, val);
    }

    @Override
    public Object deserialize(String type, String val) {
        if (!serializeMap.containsKey(type)) {
            return null;
        }
        return serializeMap.get(type).deserialize(this, val);
    }

    public record ConverterWrapper(IVarSerialize converter, int priority) implements IVarSerialize {

        @Override
        public String type() {
            return converter.type();
        }

        @Override
        public boolean isType(FlyQiuFlowVarSerializeManage manage, Object val) {
            return converter.isType(manage, val);
        }

        @Override
        public VarSerialize serialize(FlyQiuFlowVarSerializeManage manage, Object val) {
            return converter.serialize(manage, val);
        }

        @Override
        public Object deserialize(FlyQiuFlowVarSerializeManage manage, String val) {
            return converter.deserialize(manage, val);
        }
    }
}
